package cc.rengu.igas.route.core.service.trans;

import cc.rengu.igas.route.common.constant.SmartRouteParamConstant;
import cc.rengu.igas.route.common.dao.FinanceTxnRouteCustomMapper;
import cc.rengu.igas.route.common.dao.impl.FinanceTxnRouteCustomMapperImpl;
import cc.rengu.igas.route.common.enums.SmartRouteRspEnums;
import cc.rengu.igas.route.common.util.IPv4Util;
import cc.rengu.igas.route.core.helper.RouterHelper;
import cc.rengu.igas.route.core.realize.payment.DstChannelPaymentService;
import cc.rengu.igas.route.facade.request.IntelligencePaymentVerifyRequest;
import cc.rengu.igas.route.facade.response.IntelligencePaymentVerifyResponse;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.MchntOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.UserOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.MchntOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.PayOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.dao.impl.UserOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.common.enums.BizStatusEnum;
import cc.rengu.oltp.service.common.enums.OrderStatusEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.BizResponse;
import cc.rengu.oltp.service.realize.RespCodeService;
import cc.rengu.oltp.service.realize.SysParamService;
import cc.rengu.oltp.service.realize.impl.OrderServiceImpl;
import cc.rengu.oltp.service.realize.impl.RespCodeServiceImpl;
import cc.rengu.oltp.service.realize.impl.SysParamServiceImpl;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**
 * 智能路由对外收款确认
 *
 * @author xlz
 * @version 1.0
 * @date 20200423
 */
public class IntelligencePaymentVerifyService extends RadpService {
    private RgLogger rglog = RgLog.getLogger(this.getClass().getName());

    @Override
    protected int bizInit(String s) {
        return 0;
    }

    @Override
    protected int bizProcess(String s, int i) {
        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        try {
            IntelligencePaymentVerifyRequest intelligencePaymentVerifyRequest = new IntelligencePaymentVerifyRequest();
            IntelligencePaymentVerifyResponse intelligencePaymentVerifyResponse;
            ConvertUtil.convertOutput(intelligencePaymentVerifyRequest);
            if (cc.rengu.oltp.utility.util.StringUtil.isEmptyOrNull(intelligencePaymentVerifyRequest.getFrontChannelId())) {
                rglog.error("必须上送前置渠道标志[frontChannelId]");
                throw new BizException(SmartRouteRspEnums.MSG_VALID_CHECK_ERROR.getRespCode(), SmartRouteRspEnums.MSG_VALID_CHECK_ERROR.getRespDesc());
            }

            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.SRC_SYS_ID, intelligencePaymentVerifyRequest.getHeader().getSrcSysId());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.SYS_SEQ_NUM, intelligencePaymentVerifyRequest.getHeader().getTraceNo());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRANS_TIME, intelligencePaymentVerifyRequest.getHeader().getTransTime());
            xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.TRANS_DATE, intelligencePaymentVerifyRequest.getHeader().getTransDate());

            String instId = intelligencePaymentVerifyRequest.getHeader().getInstId();
            //处理附加信息
            if (!cc.rengu.oltp.utility.util.StringUtil.isEmptyOrNull(intelligencePaymentVerifyRequest.getAdditionInfo())) {
                JSONObject jsonObject = JSONObject.parseObject(intelligencePaymentVerifyRequest.getAdditionInfo());
                jsonObject.forEach((key, value) -> {
                    try {
                        xmlTreeUtil.setXmlTreeStringValue(key, (String) value);
                    } catch (Exception e) {
                        rglog.error(e.getMessage());
                    }
                });
            }
            //查询金融交易流水表获取原通道
            FinanceTxnRouteCustomMapper financeTxnMapper = new FinanceTxnRouteCustomMapperImpl();
            List<FinanceTxn> financeTxns = financeTxnMapper.fetchTxnByFrontSeqNumWithNoDateTime(
                    intelligencePaymentVerifyRequest.getHeader().getInstId(), intelligencePaymentVerifyRequest.getOrigTxnDate(),
                    intelligencePaymentVerifyRequest.getOrigOrder(), intelligencePaymentVerifyRequest.getHeader().getSrcSysId(),
                    intelligencePaymentVerifyRequest.getHeader().getChanlId());
            if (financeTxns == null) {
                //TODO 可能存在查询后发先至的问题，不能认为原交易为失败交易，若超过一定时间（一般为5-10分钟）查询不到交易则原交易一定为失败
                rglog.error("根据原交易订单号<origOrderId:{}>：未查询到流水,非查询数据库失败，认为查询交易失败返回未查询到原交易", intelligencePaymentVerifyRequest.getOrigOrder());
                throw new BizException(SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespCode(), SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespDesc());
            } else if (financeTxns.size() != 1) {
                rglog.error("根据原交易订单号：<origOrderId:{}>查询到多条", intelligencePaymentVerifyRequest.getOrigOrder());
                throw new BizException(SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespCode(), SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespDesc());
            }
            FinanceTxn financeTxn = financeTxns.get(0);
            if (financeTxn == null) {
                rglog.error("根据原交易订单号：<origOrderId:{}>", intelligencePaymentVerifyRequest.getOrigOrder());
                throw new BizException(SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespCode(), SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespDesc());
            }
            String dstChannelId = financeTxn.getDevBrand();
            MchntOrderInfo mchntOrderInfo = null;
            PayOrderInfo payOrderInfo = null;
            UserOrderInfoMapper userOrderInfoMapper = new UserOrderInfoMapperImpl();
            UserOrderInfo userOrderInfo = userOrderInfoMapper.selectUserOrderInfoByPrimaryKey(intelligencePaymentVerifyRequest.getHeader().getInstId(), financeTxn.getSysSeqNum());
            if (null == userOrderInfo) {
                //支付确认则一定收到短信等，则原来的触发短信一定成功
                rglog.error("根据原交易订单号：<origOrderId:{}>", intelligencePaymentVerifyRequest.getOrigOrder());
                throw new BizException(SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespCode(), SmartRouteRspEnums.NO_ORIG_TRANS_ERROR.getRespDesc());
            } else {
                MchntOrderInfoMapper mchntOrderInfoMapper = new MchntOrderInfoMapperImpl();
                mchntOrderInfo = mchntOrderInfoMapper.selectMchntOrderInfoByPrimaryKey(intelligencePaymentVerifyRequest.getHeader().getInstId(), financeTxn.getSysSeqNum(), financeTxn.getMchntNo());
                payOrderInfo = new PayOrderInfoMapperImpl().selectPayOrderInfoByPrimaryKey(intelligencePaymentVerifyRequest.getHeader().getInstId(), financeTxn.getSysSeqNum(), dstChannelId, "0");
            }

            String dateTime23 = DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS");
            OrderServiceImpl orderService = new OrderServiceImpl();
            //根据通道标识，通道交易码查询参数表
            SysParamService sysParamService = new SysParamServiceImpl();
            String paramType = SmartRouteParamConstant.PARAM_TYPE_PREFIX_CHANNEL_INSTANCE + dstChannelId;
            SysParam sysParam = sysParamService.getSysParamInfo(intelligencePaymentVerifyRequest.getHeader().getInstId(), paramType, financeTxn.getTxnNum());
            if (sysParam == null || StringUtil.isEmptyOrNull(sysParam.getParamValue()) || !SmartRouteParamConstant.YES.equalsIgnoreCase(sysParam.getParamStatus())) {
                rglog.error("根据通道标识<channelId:{}>，通道交易码<channelTxnId:{}>未找到当前法人<{}>或公共实现类", paramType, financeTxn.getTxnNum(), intelligencePaymentVerifyRequest.getHeader().getInstId());
                throw new BizException(SmartRouteRspEnums.CONFIG_ERROR.getRespCode(), SmartRouteRspEnums.CONFIG_ERROR.getRespDesc());
            }

            //反射获取对应服务实例
            Class c = Class.forName(sysParam.getParamValue());
            DstChannelPaymentService dstChannelPaymentService = (DstChannelPaymentService) c.newInstance();

            //通道压力+1
            boolean isIncrSucc = true;
            String keyStress = SmartRouteParamConstant.ROUTE_DATA_ALL_STRESS + ":" + AppParamConstant.DEFAULT_INSTID + ":" + dstChannelId;
            try {
                RedisUtil.onceIncr(keyStress);
            } catch (Exception e) {
                rglog.warn(cc.rengu.utility.base.StringUtil.ExceptionToString(e));
                isIncrSucc = false;
            }
            long channelStartTime = DateUtil.getCurrentTimeStamp();
            try {
                //调用通道签约确认
                intelligencePaymentVerifyResponse = dstChannelPaymentService.paymentVerify(intelligencePaymentVerifyRequest);
            } finally {
                //调用通道的结束,设置通道耗时
                long channelEndTime = DateUtil.getCurrentTimeStamp();
                String timeCost = Long.valueOf(channelEndTime - channelStartTime).toString();
                String time13 = DateUtil.getCurrentDate() + DateUtil.getCurrentTime().substring(0, 5);
                String redisKey = AppParamConstant.DEFAULT_INSTID + ":" + dstChannelId;
                String nodeKey = redisKey + ":" + IPv4Util.ipv4Address;
                String transTimeKey = SmartRouteParamConstant.ROUTE_DATA_ALL_TIMECOST + ":" + redisKey + ":" + time13;
                String transTimeNodeKey = SmartRouteParamConstant.ROUTE_DATA_ALL_TIMECOST + ":" + nodeKey + ":" + time13;
                List<String> transTimeSplitList = RedisUtil.getListRange(transTimeKey, 0, 1);
                RedisUtil.onceRightPush(transTimeKey, timeCost);
                RedisUtil.onceRightPush(transTimeNodeKey, timeCost);
                if (null == transTimeSplitList || transTimeSplitList.isEmpty()) {
                    RedisUtil.onceExpire(transTimeKey, 300);
                    RedisUtil.onceExpire(transTimeNodeKey, 300);
                }
                //通道调用成功，redis计数器自减1(通道压力减少1)
                try {
                    if (isIncrSucc) {
                        RedisUtil.onceDecr(keyStress);
                    }
                } catch (Exception e) {
                    rglog.warn("通道<{}>压力统计redis计数器压力值-1异常{}", dstChannelId, cc.rengu.utility.base.StringUtil.ExceptionToString(e));
                }
            }

            //设置返回值
            intelligencePaymentVerifyResponse.setDstChannelId(dstChannelId);
            //转换应答码状态
            RespCodeService respCodeService = new RespCodeServiceImpl();
            BizResponse response = new BizResponse();
            response.setRespCode(intelligencePaymentVerifyResponse.getRespCode());
            response.setRespDesc(intelligencePaymentVerifyResponse.getRespDesc());
            response.setRspSysId(intelligencePaymentVerifyResponse.getDstChannelId());
            TransStatusEnum transStatusEnum = respCodeService.transferRespCode(response.getRspSysId(), response.getRespCode(), response.getRespDesc());
            response.setTransStatus(transStatusEnum);
            xmlTreeUtil.deleteXmlTreeNode("status");
            if (TransStatusEnum.TRANS_SUCC.getStatus().equals(response.getTransStatus().getStatus())) {
                //成功
                intelligencePaymentVerifyResponse.setStatus("0");
                rglog.info("交易成功");
            } else if (TransStatusEnum.TRANS_INIT.getStatus().equals(response.getTransStatus().getStatus()) ||
                    TransStatusEnum.TRANS_TIMEOUT.getStatus().equals(response.getTransStatus().getStatus())) {
                //未知
                intelligencePaymentVerifyResponse.setStatus("2");
                rglog.info("交易未知");
            } else {
                //失败
                intelligencePaymentVerifyResponse.setStatus("1");
                rglog.info("交易失败");
            }
            ConvertUtil.convertInput(intelligencePaymentVerifyResponse);
            //未知不更新订单状态（目前所有代收付通道都为非实时返回代收付结果，进入不到）
            if (!TransStatusEnum.TRANS_TIMEOUT.getStatus().equals(transStatusEnum.getStatus()) && !TransStatusEnum.TRANS_INIT.getStatus().equals(transStatusEnum.getStatus())) {
                response.setTransStatus(transStatusEnum);
                if (!orderService.updateOrderInfo(updUserOrderInfo(userOrderInfo, response, dateTime23),
                        updMchntOrderInfo(mchntOrderInfo, response, dateTime23),
                        updPayOrderInfo(payOrderInfo, response, dateTime23))) {
                    rglog.error("智能路由代收更新订单失败记录应答信息到日志:");
                    rglog.error(JSON.toJSONString(response));
                }
            }
            //只统计明确成功（目前所有代收付通道都为非实时返回代收付结果，进入不到）
            if (TransStatusEnum.TRANS_SUCC.getStatus().equals(transStatusEnum.getStatus())) {
                RouterHelper.statisAmtLimit(intelligencePaymentVerifyRequest.getHeader().getInstId(), intelligencePaymentVerifyRequest.getHeader().getTxnNum(),
                        payOrderInfo.getDstTxnNum(), dstChannelId, payOrderInfo.getPayerAcctType(), payOrderInfo.getOrderAmt(), rglog);
                String keySuccCount = SmartRouteParamConstant.ROUTE_DATA_ALL_SUCC_COUNT + ":" + AppParamConstant.DEFAULT_INSTID + ":" + dstChannelId;
                try {
                    RedisUtil.onceIncr(keySuccCount);
                } catch (Exception e) {
                    rglog.warn("通道<{}>成功交易总比数统计redis计数器+1异常{}", dstChannelId, cc.rengu.utility.base.StringUtil.ExceptionToString(e));
                }
            }
        } catch (BizException e) {
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, e.getCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, e.getMessage());
            } catch (Exception e1) {
                rglog.error(cc.rengu.utility.base.StringUtil.ExceptionToString(e1));
            }
        } catch (Exception e) {
            rglog.error(cc.rengu.utility.base.StringUtil.ExceptionToString(e));
            try {
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_CODE, SmartRouteRspEnums.TRANS_FAIL.getRespCode());
                xmlTreeUtil.setXmlTreeStringValue(TreeNodeConstant.RESP_DESC, SmartRouteRspEnums.TRANS_FAIL.getRespDesc());
            } catch (Exception e1) {
                rglog.error(cc.rengu.utility.base.StringUtil.ExceptionToString(e1));
            }
        }
        return 0;
    }

    @Override
    protected int bizTerminate(String s) {
        return 0;
    }

    private UserOrderInfo updUserOrderInfo(UserOrderInfo origUserOrderInfo, BizResponse response, String dateTime23) throws Exception {
        if (TransStatusEnum.TRANS_SUCC.getStatus().equals(response.getTransStatus().getStatus())) {
            origUserOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
            origUserOrderInfo.setOrderStatus(OrderStatusEnum.FINISH.getStatus());
        } else if (TransStatusEnum.TRANS_TIMEOUT.getStatus().equals(response.getTransStatus().getStatus())) {
            origUserOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
            origUserOrderInfo.setOrderStatus(OrderStatusEnum.INIT.getStatus());
        } else if (TransStatusEnum.SYSTEM_REJECT.getStatus().equals(response.getTransStatus().getStatus())) {
            origUserOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
            origUserOrderInfo.setOrderStatus(OrderStatusEnum.CLOSE.getStatus());
        }/*else if(TransStatusEnum.SYSTEM_REJECT.getStatus().equals(response.getTransStatus().getStatus()) ){
            origUserOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
            origUserOrderInfo.setOrderStatus(OrderStatusEnum.CLOSE.getStatus());
        }*/ else {
            origUserOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
            origUserOrderInfo.setOrderStatus(OrderStatusEnum.INIT.getStatus());
        }
        origUserOrderInfo.setTransStatus(response.getTransStatus().getStatus());
        origUserOrderInfo.setUpdateTime(dateTime23);
        return origUserOrderInfo;
    }

    private List<MchntOrderInfo> updMchntOrderInfo(MchntOrderInfo origMchntOrderInfo, BizResponse response, String dateTime23) throws Exception {
        List<MchntOrderInfo> mchntOrderInfos = new ArrayList<>();
        mchntOrderInfos.add(origMchntOrderInfo);
        if (TransStatusEnum.TRANS_SUCC.getStatus().equals(response.getTransStatus().getStatus())) {
            origMchntOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
        } else if (TransStatusEnum.TRANS_TIMEOUT.getStatus().equals(response.getTransStatus().getStatus())) {
            origMchntOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        } else if (TransStatusEnum.SYSTEM_REJECT.getStatus().equals(response.getTransStatus().getStatus())) {
            origMchntOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
        }/*else if(TransStatusEnum.SYSTEM_REJECT.getStatus().equals(response.getTransStatus().getStatus()) ){
            origMchntOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
        }*/ else {
            origMchntOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        }
        origMchntOrderInfo.setTransStatus(response.getTransStatus().getStatus());
        origMchntOrderInfo.setUpdateTime(dateTime23);
        return mchntOrderInfos;
    }

    private PayOrderInfo updPayOrderInfo(PayOrderInfo origPayOrderInfo, BizResponse response, String dateTime23) throws Exception {
        if (TransStatusEnum.TRANS_SUCC.getStatus().equals(response.getTransStatus().getStatus())) {
            origPayOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
        } else if (TransStatusEnum.TRANS_TIMEOUT.getStatus().equals(response.getTransStatus().getStatus())) {
            origPayOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        } else if (TransStatusEnum.SYSTEM_REJECT.getStatus().equals(response.getTransStatus().getStatus())) {
            origPayOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
        }/*else if(TransStatusEnum.SYSTEM_REJECT.getStatus().equals(response.getTransStatus().getStatus()) ){
            origPayOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
        }*/ else {
            origPayOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        }
        origPayOrderInfo.setTransStatus(response.getTransStatus().getStatus());
        origPayOrderInfo.setUpdateTime(dateTime23);
        return origPayOrderInfo;
    }
}
